package jmine.tec.test.testsuite;

import java.lang.reflect.Constructor;
import java.util.Comparator;

import jmine.tec.test.testcase.DBTestCase;
import junit.framework.TestCase;
import bancosys.tec.utils.db.descriptor.FlatReferenceDatabaseBuilder.ReferenceDatabaseDescriptionType;

/**
 * Ordenador do refdb.
 */
final class RefdbSorter implements Comparator<Class<? extends TestCase>> {
    /**
     * Compara duas classes para garantir a ordem de execução.
     * 
     * @param o1 a primeira classe.
     * @param o2 a segunda classe.
     * @return o resultado da comparação.
     */
    @SuppressWarnings("unchecked")
    public int compare(Class<? extends TestCase> o1, Class<? extends TestCase> o2) {
        Class<? extends DBTestCase> db1 = null;
        Class<? extends DBTestCase> db2 = null;
        if (DBTestCase.class.isAssignableFrom(o1)) {
            db1 = (Class<? extends DBTestCase>) o1;
        }

        if (DBTestCase.class.isAssignableFrom(o2)) {
            db2 = (Class<? extends DBTestCase>) o2;
        }

        if (db1 == null && db2 == null) {
            return 0;
        }

        if (db1 == null) {
            return -this.getType(db2).ordinal();
        }

        if (db2 == null) {
            return this.getType(db1).ordinal();
        }

        return this.getType(db1).compareTo(this.getType(db2));
    }

    /**
     * Tipo da base de dados que a classe de teste utiliza.
     * 
     * @param cls classe de teste.
     * @return tipo da base de dados.
     */
    private ReferenceDatabaseDescriptionType getType(Class<? extends DBTestCase> cls) {
        DBTestCase testCase;
        try {
            testCase = cls.newInstance();
        } catch (InstantiationException e) {
            try {
                Constructor<? extends DBTestCase> constructor = cls.getConstructor(String.class);
                testCase = constructor.newInstance("test");
            } catch (Throwable e1) {
                throw new RuntimeException("Erro instanciando teste da classe '" + cls.getName()
                        + "' para obter tipo da base de referência.", e1);
            }
        } catch (Throwable e) {
            throw new RuntimeException("Erro instanciando teste da classe '" + cls.getName() + "' para obter tipo da base de referência.",
                    e);
        }

        return testCase.getReferenceDatabaseDescriptionType();
    }
}